package com.base.webapp.util;

import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import sun.net.www.protocol.https.Handler;


@SuppressWarnings("restriction")
public class CallbackUtils {

	private static final Log logger = LogFactory.getLog(CallbackUtils.class);
	public static final String DEFAULT_CHARSET = "GBK";
	public static final String HTTP_METHOD_POST = "POST";
	public static final String HTTP_METHOD_GET = "GET";
	public static int DEFAULT_TIMEOUT = 60000;
	public static final String HTTP_METHOD_DEFAULT = "GET";
	public static final String HTTP_PREFIX = "http://";
	public static final String HTTPS_PREFIX = "https://";

	static {
		System.setProperty("sun.net.inetaddr.ttl", "3600");
	}

	public static String httpRequest(String url, String method) throws Exception {
		return httpRequest(url, "", method, "GBK");
	}

	public static String httpRequest(String url, String queryString, String method) throws Exception {
		return httpRequest(url, queryString, method, "GBK");
	}

	public static String httpRequest(String url, Map<String, String> params, String method) throws Exception {
		return httpRequest(url, params, method, "GBK");
	}

	public static String httpPost(String url, Map<String, String> params) throws Exception {
		return httpRequest(url, params, "POST", "GBK");
	}

	public static String httpPost(String url, String queryString) throws Exception {
		return httpRequest(url, queryString, "POST", "GBK");
	}

	public static String httpGet(String url, Map<String, String> params) throws Exception {
		return httpRequest(url, params, "GET", "GBK");
	}

	public static String httpGet(String url, String queryString) throws Exception {
		return httpRequest(url, queryString, "GET", "GBK");
	}

	public static String httpRequest(String url, Map<String, String> params, String method, String charSet) throws Exception {
		String queryString = parseQueryString(params, charSet);
		return httpRequest(url, queryString, method, charSet);
	}

	public static String httpRequest(String targetUrl, String queryString, String method, String charSet)
			throws Exception {
		HttpURLConnection urlConn = null;
		URL destURL = null;
		boolean httpsFlag = false;
		if ((targetUrl == null) || (targetUrl.trim().length() == 0)) {
			throw new IllegalArgumentException("invalid targetUrl : " + targetUrl);
		}
		targetUrl = targetUrl.trim();

		if (targetUrl.toLowerCase().startsWith("https://"))
			httpsFlag = true;
		else if (!targetUrl.toLowerCase().startsWith("http://")) {
			targetUrl = "http://" + targetUrl;
		}

		if (queryString != null) {
			queryString = queryString.trim();
		}
		if ((method == null) || ((!method.equals("POST")) && (!method.equals("GET")))) {
			throw new IllegalArgumentException("invalid http method : " + method);
		}

		String baseUrl = "";
		String params = "";
		String fullUrl = "";

		int index = targetUrl.indexOf("?");
		if (index != -1) {
			baseUrl = targetUrl.substring(0, index);
			params = targetUrl.substring(index + 1);
		} else {
			baseUrl = targetUrl;
		}
		if ((queryString != null) && (queryString.trim().length() != 0)) {
			if (params.trim().length() > 0)
				params = params + "&" + queryString;
			else {
				params = params + queryString;
			}
		}

		fullUrl = baseUrl + (params.trim().length() == 0 ? "" : new StringBuilder("?").append(params).toString());

		StringBuffer result = new StringBuffer(2000);
		try {
			if (method.equals("POST")) {
				destURL = new URL(baseUrl);
				logger.info("POST方式，url：" + baseUrl);
			} else {
				destURL = new URL(null, fullUrl, new Handler());
				logger.info("GET方式，url：" + fullUrl);
			}
			if (httpsFlag) {
				trustAllHttpsCertificates();
				urlConn = (HttpsURLConnection) destURL.openConnection();
			} else {
				urlConn = (HttpURLConnection) destURL.openConnection();
			}
			urlConn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded; charset=" + charSet);
			urlConn.setDoOutput(true);
			urlConn.setDoInput(true);
			urlConn.setAllowUserInteraction(false);
			logger.info(method);
			urlConn.setUseCaches(false);
			urlConn.setRequestMethod(method);
			urlConn.setConnectTimeout(DEFAULT_TIMEOUT);
			urlConn.setReadTimeout(DEFAULT_TIMEOUT);
			urlConn.setRequestProperty("User-Agent", "EPOS");

			if (method.equals("POST")) {
				OutputStream os = urlConn.getOutputStream();
				OutputStreamWriter osw = new OutputStreamWriter(os, charSet);
				osw.write(params);
				osw.flush();
				osw.close();
			}

			BufferedInputStream is = new BufferedInputStream(urlConn.getInputStream());
			BufferedReader br = new BufferedReader(new InputStreamReader(is, charSet));
			String temp = null;
			while ((temp = br.readLine()) != null) {
				result.append(temp);
				result.append("\n");
			}
			int responseCode = urlConn.getResponseCode();
			logger.info("ResponseCode[" + responseCode + "]\n" + "result[" + result + "]");
			if (responseCode != 200) {
				return null;
			}
			return result.toString();
		} catch (Exception e) {
			logger.error("connection error : " + e.getMessage(), e);
			throw e;
		} finally {
			if (urlConn != null)
				urlConn.disconnect();
		}
	}

	public static Map<String, String> queryString(String queryResult, String splitChar) {
		String[] keyValuePairs = queryResult.split(splitChar);
		Map<String, String> map = new HashMap<>();
		for (String keyValue : keyValuePairs) {
			if (keyValue.indexOf("=") != -1) {
				String[] args = keyValue.split("=", 2);
				if (args.length == 2) {
					map.put(args[0], args[1]);
				}
				if (args.length == 1) {
					map.put(args[0], "");
				}
			}
		}
		return map;
	}

	public static String parseQueryString(Map<String, String> params, String charSet) {
		if ((params == null) || (params.keySet().size() == 0)) {
			return "";
		}
		StringBuffer queryString = new StringBuffer(2000);
		for (Iterator<String> i = params.keySet().iterator(); i.hasNext();) {
			String key = String.valueOf(i.next());
			String value = params.get(key);
			try {
				value = URLEncoder.encode(value, charSet);
			} catch (UnsupportedEncodingException ex) {
				logger.info("encode url error: " + ex.getMessage());
			}
			queryString.append(key);
			queryString.append("=");
			queryString.append(value);
			queryString.append("&");
		}
		String result = queryString.toString();
		if (result.endsWith("&")) {
			result = result.substring(0, result.length() - 1);
		}
		return result;
	}

	public static String parseUrl(String targetUrl, String queryString) {
		if ((targetUrl == null) || (targetUrl.trim().length() == 0)) {
			throw new IllegalArgumentException("invalid targetUrl : " + targetUrl);
		}
		targetUrl = targetUrl.trim();
		if ((!targetUrl.toLowerCase().startsWith("http://")) && (!targetUrl.toLowerCase().startsWith("https://"))) {
			targetUrl = "http://" + targetUrl;
		}

		if (queryString != null) {
			queryString = queryString.trim();
		}
		String baseUrl = "";
		String paramString = "";
		String fullUrl = "";
		int index = targetUrl.indexOf("?");
		if (index != -1) {
			baseUrl = targetUrl.substring(0, index);
			paramString = targetUrl.substring(index + 1);
		} else {
			baseUrl = targetUrl;
		}
		if ((queryString != null) && (queryString.trim().length() != 0)) {
			if (paramString.trim().length() > 0)
				paramString = paramString + "&" + queryString;
			else {
				paramString = paramString + queryString;
			}
		}
		fullUrl = baseUrl
				+ (paramString.trim().length() == 0 ? "" : new StringBuilder("?").append(paramString).toString());
		return fullUrl;
	}

	public static String parseUrl(String targetUrl, Map<String, String> params, String charSet) {
		String queryString = parseQueryString(params, charSet);
		return parseUrl(targetUrl, queryString);
	}

	public static Map<String, String> parseQueryString(String queryString) {
		if (queryString == null) {
			throw new IllegalArgumentException("queryString must be specified");
		}

		int index = queryString.indexOf("?");
		if (index > 0) {
			queryString = queryString.substring(index + 1);
		}

		String[] keyValuePairs = queryString.split("&");
		Map<String, String> map = new HashMap<>();
		for (String keyValue : keyValuePairs) {
			if (keyValue.indexOf("=") != -1) {
				String[] args = keyValue.split("=");
				if (args.length == 2) {
					map.put(args[0], args[1]);
				}
				if (args.length == 1)
					map.put(args[0], "");
			}
		}
		return map;
	}

	public static String parseUrl(String queryString) {
		if (queryString == null) {
			throw new IllegalArgumentException("queryString must be specified");
		}

		int index = queryString.indexOf("?");
		String targetUrl = null;
		if (index > 0)
			targetUrl = queryString.substring(0, index);
		else {
			targetUrl = queryString;
		}
		return targetUrl;
	}

	public static String parseQueryString(Map<String, String> params, String separator, String charSet) {
		if ((params == null) || (params.keySet().size() == 0)) {
			return "";
		} 
		StringBuffer queryString = new StringBuffer(2000);
		for (Iterator<String> i = params.keySet().iterator(); i.hasNext();) {
			String key = String.valueOf(i.next());
			Object obj = params.get(key);
			String value = "";
			if (obj != null)
				value = obj.toString();
			try {
				value = URLEncoder.encode(value, charSet);
			} catch (UnsupportedEncodingException ex) {
				logger.info("encode params error: " + ex.getMessage());
			}
			queryString.append(key);
			queryString.append("=");
			queryString.append(value);
			queryString.append(separator);
		}
		String result = queryString.toString();
		if (result.endsWith(separator)) {
			result = result.substring(0, result.length() - 1);
		}
		return result;
	}

	private static void trustAllHttpsCertificates() {
		try {
			TrustManager[] trustAllCerts = new TrustManager[1];
			TrustManager tm = new MyTrustManager();
			trustAllCerts[0] = tm;
			SSLContext sc = SSLContext.getInstance("SSL");
			sc.init(null, trustAllCerts, null);
			HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
			logger.debug(e);
		} catch (KeyManagementException e) {
			e.printStackTrace();
			logger.debug(e);
		} catch (Exception e) {
			e.printStackTrace();
			logger.debug(e);
		}
	}

	public static void main(String[] args) throws Exception {
		System.out.println(httpRequest("http://localhost:9000/?name=test", "", "GET", "gbk"));
	}
}
